home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / emacs.lha / emacs-19.16 / src / cm.c < prev    next >
C/C++ Source or Header  |  1993-06-06  |  10KB  |  415 lines

  1. /* Cursor motion subroutines for GNU Emacs.
  2.    Copyright (C) 1985 Free Software Foundation, Inc.
  3.     based primarily on public domain code written by Chris Torek
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. #include "config.h"
  23. #include <stdio.h>
  24. #include "cm.h"
  25. #include "termhooks.h"
  26.  
  27. #define    BIG    9999        /* 9999 good on VAXen.  For 16 bit machines
  28.                    use about 2000.... */
  29.  
  30. char *tgoto ();
  31.  
  32. extern char *BC, *UP;
  33.  
  34. int cost;        /* sums up costs */
  35.  
  36. /* ARGSUSED */
  37. evalcost (c)
  38.      char c;
  39. {
  40.   cost++;
  41. }
  42.  
  43. void
  44. cmputc (c)
  45.      char c;
  46. {
  47.   if (termscript)
  48.     fputc (c & 0177, termscript);
  49.   putchar (c & 0177);
  50. }
  51.  
  52. /* NEXT TWO ARE DONE WITH MACROS */
  53. #if 0
  54. /*
  55.  * Assume the cursor is at row row, column col.  Normally used only after
  56.  * clearing the screen, when the cursor is at (0, 0), but what the heck,
  57.  * let's let the guy put it anywhere.
  58.  */
  59.  
  60. static
  61. at (row, col) {
  62.     curY = row;
  63.     curX = col;
  64. }
  65.  
  66. /*
  67.  * Add n columns to the current cursor position.
  68.  */
  69.  
  70. static
  71. addcol (n) {
  72.     curX += n;
  73.  
  74.     /*
  75.      * If cursor hit edge of screen, what happened?
  76.      * N.B.: DO NOT!! write past edge of screen.  If you do, you
  77.      * deserve what you get.  Furthermore, on terminals with
  78.      * autowrap (but not magicwrap), don't write in the last column
  79.      * of the last line.
  80.      */
  81.  
  82.     if (curX == Wcm.cm_cols) {
  83.     /*
  84.      * Well, if magicwrap, still there, past the edge of the
  85.      * screen (!).  If autowrap, on the col 0 of the next line.
  86.      * Otherwise on last column.
  87.      */
  88.  
  89.     if (Wcm.cm_magicwrap)
  90.         ;            /* "limbo" */
  91.     else if (Wcm.cm_autowrap) {
  92.         curX = 0;
  93.         curY++;        /* Beware end of screen! */
  94.     }
  95.     else
  96.         curX--;
  97.     }
  98. }
  99. #endif
  100.  
  101. /*
  102.  * (Re)Initialize the cost factors, given the output speed of the terminal
  103.  * in the variable ospeed.  (Note: this holds B300, B9600, etc -- ie stuff
  104.  * out of <sgtty.h>.)
  105.  */
  106.  
  107. cmcostinit ()
  108. {
  109.     char *p;
  110.  
  111. #define    COST(x,e)    (x ? (cost = 0, tputs (x, 1, e), cost) : BIG)
  112. #define CMCOST(x,e)    ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e)))
  113.  
  114.     Wcm.cc_up =        COST (Wcm.cm_up, evalcost);
  115.     Wcm.cc_down =    COST (Wcm.cm_down, evalcost);
  116.     Wcm.cc_left =    COST (Wcm.cm_left, evalcost);
  117.     Wcm.cc_right =    COST (Wcm.cm_right, evalcost);
  118.     Wcm.cc_home =    COST (Wcm.cm_home, evalcost);
  119.     Wcm.cc_cr =        COST (Wcm.cm_cr, evalcost);
  120.     Wcm.cc_ll =        COST (Wcm.cm_ll, evalcost);
  121.     Wcm.cc_tab =    Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG;
  122.  
  123.     /*
  124.      * These last three are actually minimum costs.  When (if) they are
  125.      * candidates for the least-cost motion, the real cost is computed.
  126.      * (Note that "0" is the assumed to generate the minimum cost.
  127.      * While this is not necessarily true, I have yet to see a terminal
  128.      * for which is not; all the terminals that have variable-cost
  129.      * cursor motion seem to take straight numeric values.  --ACT)
  130.      */
  131.  
  132.     Wcm.cc_abs =  CMCOST (Wcm.cm_abs, evalcost);
  133.     Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost);
  134.     Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost);
  135.  
  136. #undef CMCOST
  137. #undef COST
  138. }
  139.  
  140. /*
  141.  * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using
  142.  * up and down, and left and right, motions, and tabs.  If doit is set
  143.  * actually perform the motion.
  144.  */
  145.  
  146. static
  147. calccost (srcy, srcx, dsty, dstx, doit)
  148. {
  149.     register int    deltay,
  150.                     deltax,
  151.                     c,
  152.                     totalcost;
  153.     int     ntabs,
  154.             n2tabs,
  155.             tabx,
  156.             tab2x,
  157.             tabcost;
  158.     register char  *p;
  159.  
  160.     /* If have just wrapped on a terminal with xn,
  161.        don't believe the cursor position: give up here
  162.        and force use of absolute positioning.  */
  163.  
  164.     if (curX == Wcm.cm_cols)
  165.       goto fail;
  166.  
  167.     totalcost = 0;
  168.     if ((deltay = dsty - srcy) == 0)
  169.     goto x;
  170.     if (deltay < 0)
  171.     p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
  172.     else
  173.     p = Wcm.cm_down, c = Wcm.cc_down;
  174.     if (c == BIG) {        /* caint get thar from here */
  175.     if (doit)
  176.         printf ("OOPS");
  177.     return c;
  178.     }
  179.     totalcost = c * deltay;
  180.     if (doit)
  181.     while (--deltay >= 0)
  182.         tputs (p, 1, cmputc);
  183. x: 
  184.     if ((deltax = dstx - srcx) == 0)
  185.     goto done;
  186.     if (deltax < 0) {
  187.     p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
  188.     goto dodelta;        /* skip all the tab junk */
  189.     }
  190.     /* Tabs (the toughie) */
  191.     if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
  192.     goto olddelta;        /* forget it! */
  193.  
  194.     /* 
  195.      * ntabs is # tabs towards but not past dstx; n2tabs is one more
  196.      * (ie past dstx), but this is only valid if that is not past the
  197.      * right edge of the screen.  We can check that at the same time
  198.      * as we figure out where we would be if we use the tabs (which
  199.      * we will put into tabx (for ntabs) and tab2x (for n2tabs)).
  200.      */
  201.  
  202.     ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth;
  203.     n2tabs = ntabs + 1;
  204.     tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
  205.     tab2x = tabx + Wcm.cm_tabwidth;
  206.  
  207.     if (tab2x >= Wcm.cm_cols)    /* too far (past edge) */
  208.     n2tabs = 0;
  209.  
  210.     /* 
  211.      * Now set tabcost to the cost for using ntabs, and c to the cost
  212.      * for using n2tabs, then pick the minimum.
  213.      */
  214.  
  215.            /* cost for ntabs     +    cost for right motion */
  216.     tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
  217.             : BIG;
  218.  
  219.            /* cost for n2tabs    +    cost for left motion */
  220.     c = n2tabs  ?    n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
  221.         : BIG;
  222.  
  223.     if (c < tabcost)        /* then cheaper to overshoot & back up */
  224.     ntabs = n2tabs, tabcost = c, tabx = tab2x;
  225.  
  226.     if (tabcost >= BIG)        /* caint use tabs */
  227.     goto newdelta;
  228.  
  229.     /* 
  230.      * See if tabcost is less than just moving right
  231.      */
  232.  
  233.     if (tabcost < (deltax * Wcm.cc_right)) {
  234.     totalcost += tabcost;    /* use the tabs */
  235.     if (doit)
  236.         while (--ntabs >= 0)
  237.         tputs (Wcm.cm_tab, 1, cmputc);
  238.     srcx = tabx;
  239.     }
  240.  
  241.     /* 
  242.      * Now might as well just recompute the delta.
  243.      */
  244.  
  245. newdelta: 
  246.     if ((deltax = dstx - srcx) == 0)
  247.     goto done;
  248. olddelta: 
  249.     if (deltax > 0)
  250.     p = Wcm.cm_right, c = Wcm.cc_right;
  251.     else
  252.     p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
  253.  
  254. dodelta: 
  255.     if (c == BIG) {        /* caint get thar from here */
  256. fail:
  257.     if (doit)
  258.         printf ("OOPS");
  259.     return BIG;
  260.     }
  261.     totalcost += c * deltax;
  262.     if (doit)
  263.     while (--deltax >= 0)
  264.         tputs (p, 1, cmputc);
  265. done: 
  266.     return totalcost;
  267. }
  268.  
  269. #if 0
  270. losecursor ()
  271. {
  272.   curY = -1;
  273. }
  274. #endif
  275.  
  276. #define    USEREL    0
  277. #define    USEHOME    1
  278. #define    USELL    2
  279. #define    USECR    3
  280.  
  281. cmgoto (row, col)
  282. {
  283.     int     homecost,
  284.             crcost,
  285.             llcost,
  286.             relcost,
  287.             directcost;
  288.     int     use;
  289.     char   *p,
  290.            *dcm;
  291.  
  292.   /* First the degenerate case */
  293.   if (row == curY && col == curX) /* already there */
  294.     return;
  295.  
  296.   if (curY >= 0 && curX >= 0)
  297.     {
  298.       /* We may have quick ways to go to the upper-left, bottom-left,
  299.        * start-of-line, or start-of-next-line.  Or it might be best to
  300.        * start where we are.  Examine the options, and pick the cheapest.
  301.        */
  302.  
  303.       relcost = calccost (curY, curX, row, col, 0);
  304.       use = USEREL;
  305.       if ((homecost = Wcm.cc_home) < BIG)
  306.       homecost += calccost (0, 0, row, col, 0);
  307.       if (homecost < relcost)
  308.       relcost = homecost, use = USEHOME;
  309.       if ((llcost = Wcm.cc_ll) < BIG)
  310.       llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0);
  311.       if (llcost < relcost)
  312.       relcost = llcost, use = USELL;
  313.       if ((crcost = Wcm.cc_cr) < BIG) {
  314.       if (Wcm.cm_autolf)
  315.           if (curY + 1 >= Wcm.cm_rows)
  316.           crcost = BIG;
  317.           else
  318.           crcost += calccost (curY + 1, 0, row, col, 0);
  319.       else
  320.           crcost += calccost (curY, 0, row, col, 0);
  321.       }
  322.       if (crcost < relcost)
  323.       relcost = crcost, use = USECR;
  324.       directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
  325.       if (row == curY && Wcm.cc_habs < BIG)
  326.       directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
  327.       else if (col == curX && Wcm.cc_vabs < BIG)
  328.       directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
  329.     }
  330.   else
  331.     {
  332.       directcost = 0, relcost = 100000;
  333.       dcm = Wcm.cm_abs;
  334.     }
  335.  
  336.   /* 
  337.    * In the following comparison, the = in <= is because when the costs
  338.    * are the same, it looks nicer (I think) to move directly there.
  339.    */
  340.   if (directcost <= relcost)
  341.     {
  342.       /* compute REAL direct cost */
  343.       cost = 0;
  344.       p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
  345.                    tgoto (dcm, col, row);
  346.       tputs (p, 1, evalcost);
  347.       if (cost <= relcost)
  348.     {    /* really is cheaper */
  349.       tputs (p, 1, cmputc);
  350.       curY = row, curX = col;
  351.       return;
  352.     }
  353.     }
  354.  
  355.   switch (use)
  356.     {
  357.     case USEHOME: 
  358.       tputs (Wcm.cm_home, 1, cmputc);
  359.       curY = 0, curX = 0;
  360.       break;
  361.  
  362.     case USELL: 
  363.       tputs (Wcm.cm_ll, 1, cmputc);
  364.       curY = Wcm.cm_rows - 1, curX = 0;
  365.       break;
  366.  
  367.     case USECR: 
  368.       tputs (Wcm.cm_cr, 1, cmputc);
  369.       if (Wcm.cm_autolf)
  370.     curY++;
  371.       curX = 0;
  372.       break;
  373.     }
  374.  
  375.   (void) calccost (curY, curX, row, col, 1);
  376.   curY = row, curX = col;
  377. }
  378.  
  379. /* Clear out all terminal info.
  380.    Used before copying into it the info on the actual terminal.
  381.  */
  382.  
  383. Wcm_clear ()
  384. {
  385.   bzero (&Wcm, sizeof Wcm);
  386.   UP = 0;
  387.   BC = 0;
  388. }
  389.  
  390. /*
  391.  * Initialized stuff
  392.  * Return 0 if can do CM.
  393.  * Return -1 if cannot.
  394.  * Return -2 if size not specified.
  395.  */
  396.  
  397. Wcm_init ()
  398. {
  399. #if 0
  400.   if (Wcm.cm_abs && !Wcm.cm_ds)
  401.     return 0;
  402. #endif
  403.   if (Wcm.cm_abs)
  404.     return 0;
  405.   /* Require up and left, and, if no absolute, down and right */
  406.   if (!Wcm.cm_up || !Wcm.cm_left)
  407.     return - 1;
  408.   if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
  409.     return - 1;
  410.   /* Check that we know the size of the screen.... */
  411.   if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
  412.     return - 2;
  413.   return 0;
  414. }
  415.